跳到主要内容

第7章 多线程与并发

在iOS开发中,多线程与并发是提升应用性能和用户体验的关键技术。通过合理利用多线程,我们可以在后台执行耗时操作(如网络请求、数据处理)而不影响主线程的响应性。本章将详细介绍iOS中的多线程与并发技术,包括GCD(Grand Central Dispatch)、OperationQueue以及线程安全与同步。


7.1 GCD基础

7.1.1 什么是GCD?

GCD(Grand Central Dispatch)是苹果提供的一个并发处理框架,旨在简化多线程编程的复杂性。通过GCD,开发者可以轻松地在不同线程上执行任务,而无需手动管理线程的创建和销毁。

7.1.2 GCD的核心概念

1. 队列(Queue)

队列是任务的执行序列。GCD提供了两种类型的队列:

  • 主队列(Main Queue):用于更新UI或执行需要在主线程完成的任务。
  • 全局队列(Global Queue):用于执行后台任务,支持多线程。
  • 自定义队列(Custom Queue):开发者可以根据需求创建自己的队列。

2. 任务(Task)

任务是队列中需要执行的代码块。任务可以是同步或异步的。

3. 同步与异步

  • 同步(Synchronous):任务在当前线程执行,当前线程会等待任务完成。
  • 异步(Asynchronous):任务在队列中执行,当前线程不会等待任务完成。

7.1.3 示例:使用GCD执行任务

// 创建一个全球队列
let globalQueue = DispatchQueue.global(qos: .background)

// 异步执行任务
globalQueue.async {
// 执行耗时操作
print("后台任务执行完成")

// 在主线程更新UI
DispatchQueue.main.async {
print("UI更新完成")
}
}

通过上面的代码,我们创建了一个全局队列,并在队列中异步执行了一个耗时任务。完成后,我们又在主线程中更新了UI。


7.2 OperationQueue

OperationQueue是iOS中另一个强大的并发执行工具。它与GCD类似,但提供了更多的灵活性和可管理性。

7.2.1 什么是OperationQueue?

OperationQueue用于管理和执行Operation对象。每个Operation代表一个任务,可以通过将任务添加到OperationQueue中来实现并发执行。

7.2.2 OperationQueue的核心概念

1. 并行与串行队列

  • 并行队列(Concurrent Queue):允许同时执行多个任务。
  • 串行队列(Serial Queue):任务按顺序执行。

2. 最大并行度(Max Concurrency)

通过设置maxConcurrentOperationCount,可以控制队列中同时执行的任务数量。

3. 依赖关系(Dependency)

可以设置任务之间的依赖关系,确保某些任务在其他任务完成后执行。

7.2.3 示例:使用OperationQueue执行任务

// 创建一个并行队列
let operationQueue = OperationQueue()
operationQueue.maxConcurrentOperationCount = 2

// 创建任务
let operation1 = BlockOperation {
print("任务1执行中...")
}

let operation2 = BlockOperation {
print("任务2执行中...")
}

// 添加任务到队列
operationQueue.addOperation(operation1)
operationQueue.addOperation(operation2)

通过上面的代码,我们创建了一个最大并行度为2的并行队列,并在队列中添加了两个任务。任务会同时执行。


7.3 线程安全与同步

7.3.1 什么是线程安全?

线程安全指的是多个线程可以安全地访问共享资源(如变量、数组等)而不导致数据损坏或竞态条件(Race Condition)。线程不安全的问题可能会导致程序崩溃或数据错误。

7.3.2 线程安全的常见问题

1. 共享资源的修改

当多个线程同时修改一个共享资源时,可能会导致数据竞争问题。

2. 异步操作中的UI更新

UI操作必须在主线程执行,否则会导致崩溃或不一致的UI状态。

7.3.3 线程安全的同步方法

1. 互斥锁(Mutex)

通过互斥锁可以确保同一时间只有一个线程访问共享资源。

2. 信号量(Semaphore)

信号量用于控制对共享资源的访问权限。

3. GCD的同步队列

let sharedArray =NSMutableArray()
let queue = DispatchQueue(label: "同步队列")

// 异步执行任务
queue.async {
sharedArray.add("任务1")
}

// 同步执行任务
queue.sync {
sharedArray.add("任务2")
}

通过上面的代码,我们确保对sharedArray的操作是线程安全的。


7.4 综合案例:下载图片并显示在UIImageView中

class ViewController: UIViewController {

@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var downloadButton: UIButton!

let downloadQueue = DispatchQueue.global(qos: .background)

func downloadImage(from url: String) {
downloadQueue.async {
// 模拟下载操作
Thread.sleep(forTimeInterval: 2)

// 在主线程更新UI
DispatchQueue.main.async {
self.imageView.image = UIImage(named: "example_image")
self.downloadButton.isEnabled = true
self.downloadButton.setTitle("重新下载", for: .normal)
}
}
}

@IBAction func downloadButtonTapped(_ sender: UIButton) {
downloadButton.isEnabled = false
downloadButton.setTitle("下载中...", for: .normal)
downloadImage(from: "https://example.com/image.jpg")
}
}

通过上面的代码,我们在后台队列中执行图片下载操作,并在下载完成后回到主线程更新UI。


总结来说,掌握GCD、OperationQueue以及线程安全的技巧,可以帮助我们在iOS开发中更好地利用多线程与并发技术,提升应用性能和用户体验。